
exports.__esModule = true;
exports.default = void 0;

const _utils = require('../utils');

const _style = require('../utils/dom/style');

const _event = require('../utils/dom/event');

const _raf = require('../utils/dom/raf');

const _number = require('../utils/format/number');

const _touch = require('../mixins/touch');

const _relation = require('../mixins/relation');

const _bindEvent = require('../mixins/bind-event');

// Utils
// Mixins
const _createNamespace = (0, _utils.createNamespace)('swipe');
const createComponent = _createNamespace[0];
const bem = _createNamespace[1];

const _default = createComponent({
  mixins: [_touch.TouchMixin, (0, _relation.ParentMixin)('vanSwipe'), (0, _bindEvent.BindEventMixin)(function (bind, isBind) {
    bind(window, 'resize', this.resize, true);
    bind(window, 'visibilitychange', this.onVisibilityChange);

    if (isBind) {
      this.initialize();
    } else {
      this.clear();
    }
  })],
  props: {
    width: [Number, String],
    height: [Number, String],
    autoplay: [Number, String],
    vertical: Boolean,
    lazyRender: Boolean,
    indicatorColor: String,
    loop: {
      type: Boolean,
      default: true,
    },
    duration: {
      type: [Number, String],
      default: 500,
    },
    touchable: {
      type: Boolean,
      default: true,
    },
    initialSwipe: {
      type: [Number, String],
      default: 0,
    },
    showIndicators: {
      type: Boolean,
      default: true,
    },
    stopPropagation: {
      type: Boolean,
      default: true,
    },
  },
  data: function data() {
    return {
      rect: null,
      offset: 0,
      active: 0,
      deltaX: 0,
      deltaY: 0,
      swiping: false,
      computedWidth: 0,
      computedHeight: 0,
    };
  },
  watch: {
    children: function children() {
      this.initialize();
    },
    initialSwipe: function initialSwipe() {
      this.initialize();
    },
    autoplay: function autoplay(_autoplay) {
      if (_autoplay > 0) {
        this.autoPlay();
      } else {
        this.clear();
      }
    },
  },
  computed: {
    count: function count() {
      return this.children.length;
    },
    maxCount: function maxCount() {
      return Math.ceil(Math.abs(this.minOffset) / this.size);
    },
    delta: function delta() {
      return this.vertical ? this.deltaY : this.deltaX;
    },
    size: function size() {
      return this[this.vertical ? 'computedHeight' : 'computedWidth'];
    },
    trackSize: function trackSize() {
      return this.count * this.size;
    },
    activeIndicator: function activeIndicator() {
      return (this.active + this.count) % this.count;
    },
    isCorrectDirection: function isCorrectDirection() {
      const expect = this.vertical ? 'vertical' : 'horizontal';
      return this.direction === expect;
    },
    trackStyle: function trackStyle() {
      let _ref;

      const mainAxis = this.vertical ? 'height' : 'width';
      const crossAxis = this.vertical ? 'width' : 'height';
      return _ref = {}, _ref[mainAxis] = `${this.trackSize}px`, _ref[crossAxis] = this[crossAxis] ? `${this[crossAxis]}px` : '', _ref.transitionDuration = `${this.swiping ? 0 : this.duration}ms`, _ref.transform = `translate${this.vertical ? 'Y' : 'X'}(${this.offset}px)`, _ref;
    },
    indicatorStyle: function indicatorStyle() {
      return {
        backgroundColor: this.indicatorColor,
      };
    },
    minOffset: function minOffset() {
      return (this.vertical ? this.rect.height : this.rect.width) - this.size * this.count;
    },
  },
  mounted: function mounted() {
    this.bindTouchEvent(this.$refs.track);
  },
  methods: {
    // initialize swipe position
    initialize: function initialize(active) {
      if (active === void 0) {
        active = +this.initialSwipe;
      }

      if (!this.$el || (0, _style.isHidden)(this.$el)) {
        return;
      }

      clearTimeout(this.timer);
      const rect = this.$el.getBoundingClientRect();
      this.rect = rect;
      this.swiping = true;
      this.active = active;
      this.computedWidth = Math.round(+this.width || rect.width);
      this.computedHeight = Math.round(+this.height || rect.height);
      this.offset = this.getTargetOffset(active);
      this.children.forEach((swipe) => {
        swipe.offset = 0;
      });
      this.autoPlay();
    },
    // @exposed-api
    resize: function resize() {
      this.initialize(this.activeIndicator);
    },
    onVisibilityChange: function onVisibilityChange() {
      if (document.hidden) {
        this.clear();
      } else {
        this.autoPlay();
      }
    },
    onTouchStart: function onTouchStart(event) {
      if (!this.touchable) return;
      this.clear();
      this.touchStartTime = Date.now();
      this.touchStart(event);
      this.correctPosition();
    },
    onTouchMove: function onTouchMove(event) {
      if (!this.touchable || !this.swiping) return;
      this.touchMove(event);

      if (this.isCorrectDirection) {
        (0, _event.preventDefault)(event, this.stopPropagation);
        this.move({
          offset: this.delta,
        });
      }
    },
    onTouchEnd: function onTouchEnd() {
      if (!this.touchable || !this.swiping) return;
      const { size } = this;
      const { delta } = this;
      const duration = Date.now() - this.touchStartTime;
      const speed = delta / duration;
      const shouldSwipe = Math.abs(speed) > 0.25 || Math.abs(delta) > size / 2;

      if (shouldSwipe && this.isCorrectDirection) {
        const offset = this.vertical ? this.offsetY : this.offsetX;
        let pace = 0;

        if (this.loop) {
          pace = offset > 0 ? delta > 0 ? -1 : 1 : 0;
        } else {
          pace = -Math[delta > 0 ? 'ceil' : 'floor'](delta / size);
        }

        this.move({
          pace,
          emitChange: true,
        });
      } else if (delta) {
        this.move({
          pace: 0,
        });
      }

      this.swiping = false;
      this.autoPlay();
    },
    getTargetActive: function getTargetActive(pace) {
      const { active } = this;
      const { count } = this;
      const { maxCount } = this;

      if (pace) {
        if (this.loop) {
          return (0, _number.range)(active + pace, -1, count);
        }

        return (0, _number.range)(active + pace, 0, maxCount);
      }

      return active;
    },
    getTargetOffset: function getTargetOffset(targetActive, offset) {
      if (offset === void 0) {
        offset = 0;
      }

      let currentPosition = targetActive * this.size;

      if (!this.loop) {
        currentPosition = Math.min(currentPosition, -this.minOffset);
      }

      let targetOffset = Math.round(offset - currentPosition);

      if (!this.loop) {
        targetOffset = (0, _number.range)(targetOffset, this.minOffset, 0);
      }

      return targetOffset;
    },
    move: function move(_ref2) {
      const _ref2$pace = _ref2.pace;
      const pace = _ref2$pace === void 0 ? 0 : _ref2$pace;
      const _ref2$offset = _ref2.offset;
      const offset = _ref2$offset === void 0 ? 0 : _ref2$offset;
      const { emitChange } = _ref2;
      const { loop } = this;
      const { count } = this;
      const { active } = this;
      const { children } = this;
      const { trackSize } = this;
      const { minOffset } = this;

      if (count <= 1) {
        return;
      }

      const targetActive = this.getTargetActive(pace);
      const targetOffset = this.getTargetOffset(targetActive, offset); // auto move first and last swipe in loop mode

      if (loop) {
        if (children[0] && targetOffset !== minOffset) {
          const outRightBound = targetOffset < minOffset;
          children[0].offset = outRightBound ? trackSize : 0;
        }

        if (children[count - 1] && targetOffset !== 0) {
          const outLeftBound = targetOffset > 0;
          children[count - 1].offset = outLeftBound ? -trackSize : 0;
        }
      }

      this.active = targetActive;
      this.offset = targetOffset;

      if (emitChange && targetActive !== active) {
        this.$emit('change', this.activeIndicator);
      }
    },
    // @exposed-api
    prev: function prev() {
      const _this = this;

      this.correctPosition();
      this.resetTouchStatus();
      (0, _raf.doubleRaf)(() => {
        _this.swiping = false;

        _this.move({
          pace: -1,
          emitChange: true,
        });
      });
    },
    // @exposed-api
    next: function next() {
      const _this2 = this;

      this.correctPosition();
      this.resetTouchStatus();
      (0, _raf.doubleRaf)(() => {
        _this2.swiping = false;

        _this2.move({
          pace: 1,
          emitChange: true,
        });
      });
    },
    // @exposed-api
    swipeTo: function swipeTo(index, options) {
      const _this3 = this;

      if (options === void 0) {
        options = {};
      }

      this.correctPosition();
      this.resetTouchStatus();
      (0, _raf.doubleRaf)(() => {
        let targetIndex;

        if (_this3.loop && index === _this3.count) {
          targetIndex = _this3.active === 0 ? 0 : index;
        } else {
          targetIndex = index % _this3.count;
        }

        if (options.immediate) {
          (0, _raf.doubleRaf)(() => {
            _this3.swiping = false;
          });
        } else {
          _this3.swiping = false;
        }

        _this3.move({
          pace: targetIndex - _this3.active,
          emitChange: true,
        });
      });
    },
    correctPosition: function correctPosition() {
      this.swiping = true;

      if (this.active <= -1) {
        this.move({
          pace: this.count,
        });
      }

      if (this.active >= this.count) {
        this.move({
          pace: -this.count,
        });
      }
    },
    clear: function clear() {
      clearTimeout(this.timer);
    },
    autoPlay: function autoPlay() {
      const _this4 = this;

      const { autoplay } = this;

      if (autoplay > 0 && this.count > 1) {
        this.clear();
        this.timer = setTimeout(() => {
          _this4.next();

          _this4.autoPlay();
        }, autoplay);
      }
    },
    genIndicator: function genIndicator() {
      const _this5 = this;

      const h = this.$createElement;
      const { count } = this;
      const { activeIndicator } = this;
      const slot = this.slots('indicator');

      if (slot) {
        return slot;
      }

      if (this.showIndicators && count > 1) {
        return h('div', {
          class: bem('indicators', {
            vertical: this.vertical,
          }),
        }, [Array.apply(void 0, Array(count)).map((empty, index) => h('i', {
          class: bem('indicator', {
            active: index === activeIndicator,
          }),
          style: index === activeIndicator ? _this5.indicatorStyle : null,
        }))]);
      }
    },
  },
  render: function render() {
    const h = arguments[0];
    return h('div', {
      class: bem(),
    }, [h('div', {
      ref: 'track',
      style: this.trackStyle,
      class: bem('track', {
        vertical: this.vertical,
      }),
    }, [this.slots()]), this.genIndicator()]);
  },
});

exports.default = _default;
